#include "stdafx.h"
#include "Parameter.h"
#include "LPCSTRArray.h"

LPCWSTR NOT_EXISTS_TAG = L"NOT_EXISTS_TAG";
LPCWSTR HAS_DOUBLE_CONTATION = L"[HAS_DOUBLE_CONTATION]";
LPCWSTR HAS_SINGLE_CONTATION = L"[HAS_SINGLE_CONTATION]";

IMPLEMENT_DYNAMIC(CINIOperater, CObject)

CString CINIOperater::GetString(LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const
{
	CString value;
	if (!getString(value, section, key, defaultValue)) value = defaultValue;
	return value;
}

int CINIOperater::GetInt(LPCWSTR section, LPCWSTR key, int defaultValue) const
{
	int value;
	if (!getInt(value, section, key, defaultValue)) value = defaultValue;
	return value;
}

int CINIOperater::GetIntWithRange(LPCWSTR section, LPCWSTR key, int defaultValue, int rangeMin, int rangeMax) const
{
	return max(rangeMin, min(rangeMax, GetInt(section, key, defaultValue)));
}

bool CINIOperater::GetBoolean(LPCWSTR section, LPCWSTR key, bool defaultValue) const
{
	int iValue;
	if (getInt(iValue, section, key, defaultValue ? 1 : 0)) return !!iValue;
	return defaultValue;
}

void CINIOperater::WriteBoolean(LPCWSTR section, LPCWSTR key, bool value)
{
	WriteInt(section, key, value ? 1 : 0);
}

cst_Time CINIOperater::GetTime(LPCWSTR section, LPCWSTR key, const cst_Time &defaultValue) const
{
	CString sBuf;
	if (getString(sBuf, section, key, L""))
	{
		if (sBuf.GetLength() == 8 && sBuf[2] == L':' && sBuf[5] == L':')
			return cst_Time(max(0, min(23, (sBuf[0] & 0xf) * 10 + (sBuf[1] & 0xf))),
				max(0, min(59, (sBuf[3] & 0xf) * 10 + (sBuf[4] & 0xf))), 
				max(0, min(59, (sBuf[6] & 0xf) * 10 + (sBuf[7] & 0xf))));
	}
	return defaultValue;
}

void CINIOperater::WriteTime(LPCWSTR section, LPCWSTR key, const cst_Time *pValue)
{
	if (!pValue)
		WriteString(section, key, nullptr);
	else
	{
		wchar_t sBuf[20]; swprintf_s(sBuf, L"%02d:%02d:%02d", pValue->hour, pValue->minute, pValue->second);
		WriteString(section, key, sBuf);
	}
}

CPoint CINIOperater::GetPoint(LPCWSTR section, LPCWSTR key, const CPoint &defaultValue) const
{
	CString sBuf;
	if (getString(sBuf, section, key, L""))
	{
		int i = sBuf.Find(L",");
		if (i > 0 && i < sBuf.GetLength()) return CPoint(_wtoi(sBuf.Mid(0, i)), _wtoi(sBuf.Mid(i + 1)));
	}
	return defaultValue;
}

void CINIOperater::WritePoint(LPCWSTR section, LPCWSTR key, const CPoint *pValue)
{
	if (!pValue)
		WriteString(section, key, nullptr);
	else
	{
		wchar_t sBuf[20]; swprintf_s(sBuf, L"%d,%d", pValue->x, pValue->y);
		WriteString(section, key, sBuf);
	}
}

byte CINIOperater::GetByte(LPCWSTR section, LPCWSTR key, byte defaultValue) const
{
	return (byte)GetIntWithRange(section, key, (int)defaultValue, 0, 0xff);
}

char CINIOperater::GetChar(LPCWSTR section, LPCWSTR key, char defaultValue) const
{
	return (char)GetIntWithRange(section, key, (int)defaultValue, 0, 0xff);
}

void CINIOperater::WriteByte(LPCWSTR section, LPCWSTR key, byte value)
{
	WriteInt(section, key, (int)value);
}

LPCVOID CINIOperater::ReadArray(LPCWSTR section, LPCWSTR key, intptr_t &num, IArrayCallback *callback) const
{
	num = 0; intptr_t n = GetInt(section, key, 0); if (n <= 0) return nullptr;
	CString sec; sec.Format(L"%s\\%s_Item", section, key);
	LPCVOID data = callback->allocElement(n); if (!data) return nullptr;
	num = n; for (intptr_t i = 0; i < num; i++)
	{
		CString k; k.Format(L"n%d", (int)i); callback->readElement(this, sec, k, data, i);
	}
	return data;
}

void CINIOperater::WriteArray(LPCWSTR section, LPCWSTR key, LPCVOID data, intptr_t num, const IArrayCallback *callback)
{
	if (!data)
		clearKey(section, key);
	else
	{
		WriteInt(section, key, (int)num); CString sec; sec.Format(L"%s\\%s_Item", section, key); 
		for (intptr_t i = 0; i < num; i++)
		{
			CString k; k.Format(L"n%d", (int)i); callback->writeElement(this, sec, k, data, i);
		}
	}
}


void CINIOperater::FormatSection(LPCWSTR sec_in, LPCWSTR key_in, LPWSTR sec, LPWSTR key) const
{
	intptr_t lm = -1;
	for (LPCWSTR f = key_in;;)
	{
		f = wcsstr(f, L"\\"); if (!f) break;
		lm = f - key_in; f++;
	}
	if (lm < 0)
	{
		if (sec_in) wcscpy_s(sec, 100, sec_in); else sec[0] = 0;
		wcscpy_s(key, 100, key_in);
	}
	else
	{
		wchar_t tmpKey[100]; wcscpy_s(tmpKey, key_in); tmpKey[lm] = 0;
		if (sec_in) swprintf_s(sec, 100, L"%s\\%s", sec_in, tmpKey); else wcscpy_s(sec, 100, tmpKey);
		wcscpy_s(key, 100, key_in + lm + 1);
	}
	while (sec[0] == L'\\') wcscpy_s(sec, 100, sec + 1);
}

CString CINIOperater::FormatToString(CString value) const
{
	int dl = (int)wcslen(HAS_DOUBLE_CONTATION), sl = (int)wcslen(HAS_SINGLE_CONTATION);
	if (value.GetLength() >= dl && value.Left(dl) == HAS_DOUBLE_CONTATION)
		return L"\"" + value.Mid(dl) + L"\"";
	else if (value.GetLength() >= sl && value.Left(sl) == HAS_SINGLE_CONTATION)
		return L"'" + value.Mid(sl) + L"'";
	else
		return value;
}

CString CINIOperater::StringToFormat(LPCWSTR value) const
{
	CString sValue = value;
	if (wcslen(value) >= 2)
	{
		if (value[0] == L'"' && value[wcslen(value) - 1] == L'"')
		{
			CString v = sValue.Mid(1, sValue.GetLength() - 2);
			sValue = HAS_DOUBLE_CONTATION + v;
		}
		else if (value[0] == L'\'' && value[wcslen(value) - 1] == L'\'')
		{
			CString v = sValue.Mid(1, sValue.GetLength() - 2);
			sValue = HAS_SINGLE_CONTATION + v;
		}
	}
	return sValue;
}


extern CWinApp *mainApp;
//CINIOperaterDefault
IMPLEMENT_DYNAMIC(CINIOperaterDefault, CINIOperater)
bool CINIOperaterDefault::getString(CString &value, LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	value = FormatToString(mainApp->GetProfileString(sec, keyout, defaultValue));
	return true;
}

void CINIOperaterDefault::WriteString(LPCWSTR section, LPCWSTR key, LPCWSTR value)
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	if (value)
		mainApp->WriteProfileString(sec, keyout, StringToFormat(value));
	else
		mainApp->WriteProfileString(sec, keyout, NULL);
}

bool CINIOperaterDefault::getInt(int &value, LPCWSTR section, LPCWSTR key, int defaultValue) const
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	value = mainApp->GetProfileInt(sec, keyout, defaultValue);
	return true;
}

void CINIOperaterDefault::WriteInt(LPCWSTR section, LPCWSTR key, int value)
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	mainApp->WriteProfileInt(sec, keyout, value);
}

bool CINIOperaterDefault::hasSection(LPCWSTR sec) const
{
	HKEY hKey = mainApp->GetAppRegistryKey(); if (!hKey) return false;
	bool bRet;
	if (!sec || wcslen(sec) <= 0)
		bRet = true;
	else
	{
		bRet = false;
		for (intptr_t i = 0; sec[i];)
		{
			wchar_t subSec[100];
			intptr_t j = 0; for (; sec[i] && sec[i] != L'\\'; i++, j++) subSec[j] = sec[i];
			subSec[j] = 0; if (sec[i] == L'\\') i++;
			if (!RegItemExists(hKey, subSec, true)) break;
			if (sec[i] == 0)
			{
				bRet = true; break;
			}
			HKEY nextKey = nullptr;
			if (RegOpenKeyEx(hKey, subSec, 0, KEY_READ, &nextKey) != ERROR_SUCCESS)
			{
				if (nextKey) RegCloseKey(hKey);
				break;
			}
			RegCloseKey(hKey); hKey = nextKey;
		}
	}
	RegCloseKey(hKey);
	return bRet;
}

bool CINIOperaterDefault::hasKey(LPCWSTR section, LPCWSTR key) const
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	if (!hasSection(sec)) return false;
	HKEY hKey = mainApp->GetSectionKey(sec); if (!hKey) return false;
	bool bRet = RegItemExists(hKey, keyout, false);
	RegCloseKey(hKey);
	return bRet;
}

bool CINIOperaterDefault::RegItemExists(HKEY hKey, LPCWSTR name, bool isKey) const
{
	DWORD cNum = 0;
	if (RegQueryInfoKey(hKey, NULL, NULL, NULL, (isKey ? &cNum : NULL), NULL, NULL,
			(!isKey ? &cNum : NULL), NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
		return false;
	for (DWORD i = 0; i<cNum; i++)
	{
		wchar_t itemName[16384]; DWORD nameLength = 16384; itemName[0] = '\0';
		if (isKey)
		{
			if (RegEnumKeyEx(hKey, i, itemName, &nameLength, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
		}
		else
		{
			if (RegEnumValue(hKey, i, itemName, &nameLength, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
		}
		if (wcscmp(itemName, name) == 0)
			return true;
	}
	return false;
}
LPCWSTR CINIOperaterDefault::enumKeys(LPCWSTR section) const
{
	if (!hasSection(section)) return nullptr;
	HKEY hKey = mainApp->GetSectionKey(section); if (!hKey) return nullptr;
	CString result; DWORD cNum = 0;
	if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &cNum, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
		for (DWORD i = 0; i < cNum; i++)
		{
			wchar_t itemName[16384]; DWORD nameLength = 16384; itemName[0] = '\0';
			if (RegEnumValue(hKey, i, itemName, &nameLength, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
			if (i) result += L"\x9";
			result += itemName;
		}
	RegCloseKey(hKey);
	return result.IsEmpty() ? nullptr : copyStr((LPCWSTR)result);
}


//CINIOperaterFile
IMPLEMENT_DYNAMIC(CINIOperaterFile, CINIOperater)
bool CINIOperaterFile::getString(CString &value, LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	wchar_t sBuf[1024];
	intptr_t i = GetPrivateProfileString(sec, keyout, NOT_EXISTS_TAG, sBuf, 1024, m_iniFile);
	if (wcscmp(sBuf, NOT_EXISTS_TAG) == 0) return false;
	sBuf[i] = 0; value = FormatToString(sBuf);
	return true;
}
void CINIOperaterFile::WriteString(LPCWSTR section, LPCWSTR key, LPCWSTR value)
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	if (value)
		WritePrivateProfileString(sec, keyout, StringToFormat(value), m_iniFile);
	else
		WritePrivateProfileString(sec, keyout, nullptr, m_iniFile);
}
bool CINIOperaterFile::getInt(int &value, LPCWSTR section, LPCWSTR key, int defaultValue) const
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	if (!hasKey(sec, keyout)) return false;
	value = GetPrivateProfileInt(sec, keyout, defaultValue, m_iniFile);
	return true;
}
void CINIOperaterFile::WriteInt(LPCWSTR section, LPCWSTR key, int value)
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	wchar_t sValue[20]; swprintf_s(sValue, L"%d", value);
	WritePrivateProfileString(sec, keyout, sValue, m_iniFile);
}
bool CINIOperaterFile::hasSection(LPCWSTR sec) const
{
	FILE * f = _wfsopen(m_iniFile, L"rt", _SH_DENYWR); bool found = false;
	if (f)
	{
		for (;;)
		{
			wchar_t buf[1024]; fgetws(buf, 1024, f); if (feof(f)) break;
			intptr_t n = wcslen(buf); for (; n > 0 && buf[n - 1] == L'\r' || buf[n - 1] == L'\n'; n--);
			if (n > 0 && buf[0] == L'[' && buf[n - 1] == L']')
			{
				buf[n - 1] = 0; if (wcscmp(buf + 1, sec) == 0) { found = true; break; }
				intptr_t l = wcslen(sec);
				if (wcsncmp(sec, buf + 1, l) == 0 && *(buf + l + 1) == L'\\') { found = true; break; }
			}
		}
		fclose(f);
	}
	return found;
	/*
	wchar_t sBuf[10240];
	intptr_t length = GetPrivateProfileSectionNames(sBuf, 10240, m_iniFile);
	for (intptr_t i = 0; (sBuf + i)[0] && i < length; i += wcslen(sBuf + i) + 1)
	{
		if (wcscmp(sec, sBuf + i) == 0) return true;
		intptr_t l = wcslen(sec);
		if (wcsncmp(sec, sBuf + i, l) == 0 && sBuf[i + l] == L'\\') return true;
	}
	return false;
	*/
}
bool CINIOperaterFile::hasKey(LPCWSTR sec, LPCWSTR keyout) const
{
	wchar_t sBuf[1024];
	GetPrivateProfileString(sec, keyout, NOT_EXISTS_TAG, sBuf, 1024, m_iniFile);
	return wcscmp(sBuf, NOT_EXISTS_TAG) == 0 ? false : true;
}
LPCWSTR CINIOperaterFile::enumKeys(LPCWSTR section) const
{
	if (!hasSection(section)) return nullptr;
	wchar_t sBuf[40960]; intptr_t length = GetPrivateProfileString(section, nullptr, NOT_EXISTS_TAG, sBuf, 40960, m_iniFile);
	if (wcscmp(sBuf, NOT_EXISTS_TAG) == 0) return nullptr;
	for (intptr_t i = 0; i < length && sBuf[i]; i++)
	{
		i += wcslen(sBuf + i); if (i + 1 >= length || sBuf[i + 1] == 0) break;
		sBuf[i] = L'\x9';
	}
	return copyStr(sBuf);
}





//CINIOperaterJson
IMPLEMENT_DYNAMIC(CINIOperaterJson, CINIOperater)
bool CINIOperaterJson::getString_real(CString &value, LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	bool bRet = false;
	do {
		const Json::Value *v = GetField(sec[0] ? sec : nullptr); if (!v || v->empty() || !v->isObject()) break;
		LPCSTR pKey = WideToLPSTR(keyout, CP_ACP);
		if (pKey)
		{
			if (v->isMember(pKey) && (*v)[pKey].isString())
			{
				LPCWSTR pValue = StringToWide((*v)[pKey].asString(), CP_ACP);
				value = pValue ? FormatToString(pValue) : L"";
				if (pValue) HeapFree(GetProcessHeap(), 0, (LPVOID)pValue);
				bRet = true;
			}
			HeapFree(GetProcessHeap(), 0, (LPVOID)pKey);
		}
		else if ((*v).isString())
		{
			LPCWSTR pValue = StringToWide((*v).asString(), CP_ACP);
			value = pValue ? FormatToString(pValue) : L"";
			if (pValue) HeapFree(GetProcessHeap(), 0, (LPVOID)pValue);
			bRet = true;
		}
	} while (0);
	return bRet;
}
bool CINIOperaterJson::getString(CString &value, LPCWSTR section, LPCWSTR key, LPCWSTR defaultValue) const
{
	__try {
		return getString_real(value, section, key, defaultValue);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		return false;
	}
}
void CINIOperaterJson::WriteString(LPCWSTR section, LPCWSTR key, LPCSTR value)
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	Json::Value *v = GetField(sec[0] ? sec : nullptr, true);
	LPCSTR pKey = WideToLPSTR(keyout, CP_ACP);
	if (pKey)
	{
		(*v)[pKey] = value ? value : "";
		HeapFree(GetProcessHeap(), 0, (LPVOID)pKey);
	}
	else
		(*v) = value ? value : "";
}
void CINIOperaterJson::WriteString(LPCWSTR section, LPCWSTR key, LPCWSTR value)
{
	LPCSTR pValue = value ? WideToLPSTR(StringToFormat(value), CP_ACP) : nullptr;
	WriteString(section, key, pValue);
	if (pValue) HeapFree(GetProcessHeap(), 0, (LPVOID)pValue);
}
bool CINIOperaterJson::getInt_real(int &value, LPCWSTR section, LPCWSTR key, int defaultValue) const
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	bool bRet = false;
	do {
		const Json::Value *v = GetField(sec[0] ? sec : nullptr); if (!v || v->empty() || !v->isObject()) break;
		LPCSTR pKey = WideToLPSTR(keyout, CP_ACP);
		if (pKey)
		{
			if (v->isMember(pKey) && (*v)[pKey].isInt())
			{
				value = (*v)[pKey].asInt();
				bRet = true;
			}
			if (pKey) HeapFree(GetProcessHeap(), 0, (LPVOID)pKey);
		}
		else if ((*v).isInt())
		{
			value = (*v).asInt();
			bRet = true;
		}
	} while (0);
	return bRet;
}
bool CINIOperaterJson::getInt(int &value, LPCWSTR section, LPCWSTR key, int defaultValue) const
{
	__try {
		return getInt_real(value, section, key, defaultValue);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		return false;
	}
}
void CINIOperaterJson::WriteInt(LPCWSTR section, LPCWSTR key, int value)
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	Json::Value *v = GetField(sec[0] ? sec : nullptr, true);
	LPCSTR pKey = WideToLPSTR(keyout, CP_ACP);
	if (pKey)
	{
		(*v)[pKey] = value;
		HeapFree(GetProcessHeap(), 0, (LPVOID)pKey);
	}
	else
		*v = value;
}
Json::Value* CINIOperaterJson::GetField_real(LPCWSTR section, bool addWhenNotExists)
{
	CLPCSTRArray fPath(section, "\\", CP_ACP); Json::Value *v = &m_root;
	for (intptr_t i = 0; i < fPath.count; i++)
	{
		if (!v->isMember(fPath.str[i]))
		{
			if (!addWhenNotExists) return nullptr;
			Json::Value newSeg;
			(*v)[fPath.str[i]] = newSeg;
		}
		v = &((*v)[fPath.str[i]]);
	}
	return v;
}
Json::Value* CINIOperaterJson::GetField(LPCWSTR section, bool addWhenNotExists)
{
	__try {
		return GetField_real(section, addWhenNotExists);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		return nullptr;
	}
}
const Json::Value* CINIOperaterJson::GetField(LPCWSTR section) const
{
	__try {
		return ((CINIOperaterJson*)this)->GetField_real(section, false);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		return nullptr;
	}
}
LPCSTR CINIOperaterJson::getJsonString_real()
{
	if (!m_root.empty())
		return copyStr(m_root.toFastString(false).c_str());
	else
		return nullptr;
}
LPCSTR CINIOperaterJson::getJsonString()
{
	__try {
		return getJsonString_real();
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		return nullptr;
	}
}
bool CINIOperaterJson::buildJson_real(LPCSTR orgStr)
{
	m_root.clear();
	if (orgStr)
	{
		Json::Reader reader;
		if (!reader.parse(orgStr, m_root)) return false;
	}
	return true;
}
bool CINIOperaterJson::buildJson(LPCSTR orgStr)
{
	__try {
		return buildJson_real(orgStr);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		return false;
	}
}

void CINIOperaterJson::WriteBool(LPCWSTR section, LPCWSTR key, bool value)
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	Json::Value *v = GetField(sec[0] ? sec : nullptr, true);
	LPCSTR pKey = WideToLPSTR(keyout, CP_ACP);
	if (pKey)
	{
		(*v)[pKey] = value;
		HeapFree(GetProcessHeap(), 0, (LPVOID)pKey);
	}
	else
		(*v) = value;
}
bool CINIOperaterJson::hasSection(LPCWSTR section) const
{
	wchar_t sec[100]; wcscpy_s(sec, section);
	while (sec[0] == L'\\') wcscpy_s(sec, 100, sec + 1);
	return GetField(sec[0] ? sec : nullptr) != nullptr;
}
bool CINIOperaterJson::hasKey(LPCWSTR section, LPCWSTR key) const
{
	wchar_t sec[100]; swprintf_s(sec, L"%s\\%s", section, key);
	while (sec[0] == L'\\') wcscpy_s(sec, 100, sec + 1);
	return GetField(sec) != nullptr;
}
void CINIOperaterJson::clearKey(LPCWSTR section, LPCWSTR key)
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	Json::Value *v = GetField(sec[0] ? sec : nullptr, false); if (!v) return;
	LPCSTR pKey = WideToLPSTR(keyout, CP_ACP);
	if (pKey)
	{
		v->removeMember(pKey);
		HeapFree(GetProcessHeap(), 0, (LPVOID)pKey);
	}
}
LPCWSTR CINIOperaterJson::enumKeys(LPCWSTR section) const
{
	wchar_t sec[100]; wcscpy_s(sec, section);
	while (sec[0] == L'\\') wcscpy_s(sec, 100, sec + 1);
	const Json::Value *v = GetField(sec[0] ? sec : nullptr); if (!v) return nullptr;
	Json::Value::Members mem = v->getMemberNames(); std::string result;
	for (Json::Value::Members::iterator it = mem.begin(); it != mem.end(); ++it)
	{
		if (result.empty()) result += "\x9";
		result += *it;
	}
	return result.empty() ? nullptr : LPSTRToWide(result.c_str(), -1, CP_ACP);
}
LPCVOID CINIOperaterJson::ReadArray_real(LPCWSTR section, LPCWSTR key, intptr_t &num, IArrayCallback *callback) const
{
	wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
	LPCVOID data = nullptr; num = 0;
	do {
		const Json::Value *v = GetField(sec[0] ? sec : nullptr); if (!v || v->empty() || !v->isObject()) break;
		LPCSTR pKey = WideToLPSTR(keyout, CP_ACP); const Json::Value *ary = nullptr;
		if (pKey)
		{
			if (v->isMember(pKey) && (*v)[pKey].isArray()) ary = &(*v)[pKey];
			if (pKey) HeapFree(GetProcessHeap(), 0, (LPVOID)pKey);
		}
		else if (v->isArray())
			ary = v;
		if (!ary) break;
		intptr_t n = ary->size(); if (n <= 0) break;
		data = callback->allocElement(n); if (!data) break;
		num = n; for (intptr_t i = 0; i < num; i++)
		{
			CINIOperaterJson operJ; if (!(*ary)[(int)i].isNull()) operJ.m_root["n"] = (*ary)[(int)i];
			callback->readElement(&operJ, L"", L"n", data, i);
		}
	} while (0);
	return data;
}
LPCVOID CINIOperaterJson::ReadArray(LPCWSTR section, LPCWSTR key, intptr_t &num, IArrayCallback *callback) const
{
	__try {
		return ReadArray_real(section, key, num, callback);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		return false;
	}
}
void CINIOperaterJson::WriteArray(LPCWSTR section, LPCWSTR key, LPCVOID data, intptr_t num, const IArrayCallback *callback)
{
	if (!data)
		clearKey(section, key);
	else
	{
		CINIOperaterJson operJ; Json::Value ary;
		for (intptr_t i = 0; i < num; i++)
		{
			operJ.m_root.clear(); callback->writeElement(&operJ, L"", L"n", data, i); ary.append(operJ.m_root["n"]);
		}
		wchar_t sec[100], keyout[100]; FormatSection(section, key, sec, keyout);
		Json::Value *v = GetField(sec[0] ? sec : nullptr, true);
		LPCSTR pKey = WideToLPSTR(keyout, CP_ACP);
		if (pKey)
		{
			(*v)[pKey] = ary;
			HeapFree(GetProcessHeap(), 0, (LPVOID)pKey);
		}
		else
			(*v) = ary;
	}
}
